#ifndef _TS_STREAM_DEMUXER_
#define _TS_STREAM_DEMUXER_

#include <map>
#include <stdint.h>
#include <string.h>

#define AUDIO_BUFFER_SIZE 1024
#define VIODE_BUFFER_SIZE 1920*1080*2

namespace tsde_status
{
	enum status
	{
		status_demux_err 			= -1,
		status_demux_more_data		= 0,
		status_demux_ok 			= 1,
		status_demux_unkonw			= 2
	};
};

namespace stream_type
{
	enum stype
	{
		data                = 0,
		mpeg2_video         = 1,
		h264_video          = 2,
		vc1_video           = 3,
		ac3_audio           = 4,
		mpeg2_audio         = 5,
		lpcm_audio          = 6,
		dts_audio           = 7,
		aac_audio			= 8
	};
};

class table
{
	public:
	enum { max_buf_len=512 };

	char buf[max_buf_len];

    uint16_t len;

    uint16_t offset;

    table(void):offset(0),len(0) {}

    inline void reset(void) { offset=0; len=0; }
};


class stream
{
	public:
    uint16_t channel;                      // channel number (1,2 ...)
    uint8_t  id;                           // stream number in channel
    uint8_t  type;                         // 0xff                 - not ES
    									   // 0x01,0x02            - MPEG2 video
                                           // 0x80                 - MPEG2 video (for TS only, not M2TS)
                                           // 0x1b                 - H.264 video
                                           // 0xea                 - VC-1  video
                                           // 0x81,0x06,0x83       - AC3   audio
                                           // 0x03,0x04            - MPEG2 audio
                                           // 0x80                 - LPCM  audio
                                           // 0x82,0x86,0x8a       - DTS   audio
    									   // 0x11,0x0f		       - AAC   audio

    table psi;                              // PAT,PMT cache (only for PSI streams)

    uint8_t stream_id;                     // MPEG stream id

    uint64_t dts;                          // current MPEG stream DTS (presentation time for audio, decode time for video)
    uint64_t first_dts;
    uint64_t first_pts;
    uint64_t last_pts;
    uint32_t frame_length;                 // frame length in ticks (90 ticks = 1 ms, 90000/frame_length=fps)
    uint64_t frame_num;                    // frame counter

    int	frame_len;
    uint32_t timestamp;
    uint8_t *buffer[2];

    stream(void):channel(0xffff),id(0),type(0xff),stream_id(0),
    		dts(0),first_dts(0),first_pts(0),last_pts(0),frame_length(0),frame_num(0),frame_len(0),timestamp(0)
    {
    	buffer[0] = 0;
    	buffer[1] = 0;
    }

    ~stream(void)
    {
    	if(buffer[0])
    	{
    		delete [] buffer[0];
    	}
    	if(buffer[1])
    	{
    		delete [] buffer[1];
    	}
    };

    inline void reset(void)
    {
    	psi.reset();
        dts=first_pts=last_pts=0;
        frame_length=0;
        frame_num=0;
    }
};


class tsDemuxer
{
public:

	tsDemuxer();
	~tsDemuxer();
	tsde_status::status demuxTsPackets(const char* ts_data,int ts_len,uint8_t** frame_out,int *frame_len,uint32_t *timestamp,stream_type::stype *type);
	tsde_status::status demuxATsPacket(const char* ts_data,uint8_t** frame_out,int *frame_len,uint32_t *timestamp,stream_type::stype *type);

private:
	int getStreamType(uint8_t type);
	const char* getStreamExt(uint8_t type_id);
	bool validateType(uint8_t type);
	uint64_t decodePts(const char* ptr);
private:
	uint8_t toByte(const char* p);
	uint16_t toInt(const char* p);
	uint32_t toInt32(const char* p);
private:
	std::map<uint16_t,stream> m_streams;
	int m_channel;   // channel for demux
};

#endif
